package com.zfsmart.component.common.util;

import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
 * 字符串相关操作
 *
 * @author HUMZ
 * @version 1.0
 */
@Slf4j
public class StringUtil {
    public static final String SPACE = " ";
    public static final String DOT = ".";
    public static final String SLASH = "/";
    public static final String BACKSLASH = "\\";
    public static final String EMPTY = "";
    public static final String CRLF = "\r\n";
    public static final String NEWLINE = "\n";
    public static final String UNDERLINE = "_";
    public static final String COMMA = ",";

    public static final String HTML_NBSP = "&nbsp;";
    public static final String HTML_AMP = "&amp";
    public static final String HTML_QUOTE = "&quot;";
    public static final String HTML_LT = "&lt;";
    public static final String HTML_GT = "&gt;";

    public static final String J2EE_WEB_INF = "WEB-INF";

    public static final String EMPTY_JSON = "{}";

    public static List<String> splitStr(String targetStr, String splitChar,
                                        boolean filterSpace, boolean isNoAddSpace) {

        List<String> list = new ArrayList<String>();
        if (targetStr == null)
            return list;
        if (splitChar == null || splitChar.equals("")) {
            if (filterSpace)
                list.add(targetStr.trim());
            else
                list.add(targetStr);
            return list;
        }
        int splitCharLength = splitChar.length();
        int index;
        for (int i = -splitCharLength; i < targetStr.length(); i = index) {
            index = targetStr.indexOf(splitChar, i + splitCharLength);
            if (index < 0)
                index = targetStr.length();
            String temp = targetStr.substring(i + splitCharLength, index);
            if (filterSpace)
                temp = temp.trim();
            if (!isNoAddSpace || temp.length() > 0)
                list.add(temp);
        }
        return list;
    }

    /**
     * @param targetStr
     * @param beReplace
     * @param replace
     * @return
     */
    public static String replace(String targetStr, String beReplace,
                                 String replace) {

        if (targetStr == null)
            return null;
        if (beReplace == null || beReplace.equals(""))
            return targetStr;
        if (replace == null)
            replace = "";
        StringBuffer stringbuffer = new StringBuffer();
        int i = 0;
        int index = targetStr.indexOf(beReplace);
        int length = beReplace.length();
        for (; index > -1; index = targetStr.indexOf(beReplace, i)) {
            stringbuffer.append(targetStr.substring(i, index) + replace);
            i = index + length;
        }
        stringbuffer.append(targetStr.substring(i));
        return stringbuffer.toString();
    }

    /**
     * @param targetStr
     * @param beReplace
     * @param replace
     * @return
     */
    public static String replaceIgnoreCase(String targetStr, String beReplace,
                                           String replace) {

        if (targetStr == null)
            return null;
        if (beReplace == null || beReplace.equals(""))
            return targetStr;
        if (replace == null)
            replace = "";
        String targetStrLower = targetStr.toLowerCase();
        String beReplaceLower = beReplace.toLowerCase();
        StringBuffer stringbuffer = new StringBuffer();
        int i = 0;
        int index = targetStrLower.indexOf(beReplaceLower);
        int length = beReplace.length();
        for (; index > -1; index = targetStrLower.indexOf(beReplaceLower, i)) {
            stringbuffer.append(targetStr.substring(i, index) + replace);
            i = index + length;
        }
        stringbuffer.append(targetStr.substring(i));
        return stringbuffer.toString();
    }

    public static String flushLeft(String c, long length, String content) {
        String str = "";
        String cs = "";
        if (content.length() > length) {
            str = content;
        } else {
            for (int i = 0; i < length - content.length(); i++) {
                cs = cs + c;
            }
        }
        str = cs + content;
        return str;
    }

    public static String spliter(String str) {
        if (str == null)
            return "";
        str = str.trim();
        return str;
    }

    public static boolean isBlank(String str) {
        return str == null || str.trim().length() == 0;
    }

    public static boolean isNotBlank(String str) {
        return false == isBlank(str);
    }

    public static boolean isEmpty(String str) {
        return str == null || str.length() == 0;
    }

    public static boolean isNotEmpty(String str) {
        return false == isEmpty(str);
    }

    public static boolean isNumber(String obj) {
        if (null == obj) {
            obj = "";
        }
        return obj.matches("-?\\d+\\.?\\d*");
    }

    public static String obj2String(Object object) {
        if (object == null)
            return "";
        if (object instanceof String) {
            if ("null".equalsIgnoreCase((String) object)) {
                return "";
            }
        }
        return String.valueOf(object);
    }

    /**
     * 字母Z使用了两个标签，这里有27个值
     * <p>
     * i, u, v都不做声母, 跟随前面的字母
     */
    private char[] chartable = {'啊', '芭', '擦', '搭', '蛾', '发', '噶', '哈', '哈',
            '击', '喀', '垃', '妈', '拿', '哦', '啪', '期', '然', '撒', '塌', '塌', '塌',
            '挖', '昔', '压', '匝', '座'};

    private static char[] alphatable = {'A', 'B', 'C', 'D', 'E', 'F', 'G',
            'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
            'U', 'V', 'W', 'X', 'Y', 'Z'};

    /**
     * 获取命名参数SQL的命名参数名称
     *
     * @param namedParameterSql 获取命名参数SQL<br>
     *                          如 and name1 = :NAME1 and name2 =:NAME2<br>
     *                          命名参数SQL必须规范 各字符串间用空格分隔
     * @return 命名参数名称数组 如["NAME1","NAME2"]
     */
    public static String[] getNamedParameterArray(String namedParameterSql) {
        String regex1 = ":";

        String[] arr1 = namedParameterSql.split(regex1);
        String[] strArray = new String[arr1.length - 1];
        String NamedParameter = "";
        for (int i = 1; i < arr1.length; i++) {
            int endIndex = arr1[i].indexOf(" ");
            if (endIndex > 0) {
                NamedParameter = arr1[i].substring(0, endIndex);
                strArray[i - 1] = NamedParameter.trim();
            } else {
                strArray[i - 1] = arr1[i].trim();
            }
        }
        return strArray;
    }

    /**
     * 判断字符串为空(null)或空字符串("")或null字符串("null")
     *
     * @param str 需要判断的字符串
     * @return 为空返回true，不为空返回false
     */
    public static boolean isNull(String str) {
        boolean rtn = true;
        if (str != null && !str.equals("") && !str.equals("null")) {
            rtn = false;
        }
        return rtn;

    }

    /**
     * 处理最后一位是逗号的字符串
     *
     * @param str 需要处理的字符串
     * @return 字符串 如果最后一位逗号，则去除最后一位
     */
    public static String cutLastStr(String str) {
        if (isNotEmpty(str)) {
            if (str.lastIndexOf(",") == str.length() - 1) {
                return str.substring(0, str.length() - 1);
            } else {
                return str;
            }
        } else {
            return null;
        }
    }

    /**
     * 格式化字符串到指定位数，前面补0
     *
     * @param sVal 需要补0字符串
     * @param iLen 总位数
     * @return
     */
    public static String appendZero(String sVal, int iLen) {
        String sRet = getRepeatChar('0', iLen - sVal.length()).append(sVal)
                .toString();
        return sRet;
    }

    /**
     * @param c
     * @param repeat
     * @return
     */
    private static StringBuffer getRepeatChar(char c, int repeat) {
        StringBuffer retStrBuf = new StringBuffer();
        for (int i = 0; i < repeat; i++) {
            retStrBuf.append(c);
        }
        return retStrBuf;
    }

    /**
     * 返回oracle错误信息中的有用信息 例如：ORA-01401：插入的值对于列过大，则返回"插入的值对于列过大"
     *
     * @param oraErr
     * @return
     */
    public static String fetchOraUseFulInfo(String oraErr) {
        if (oraErr.indexOf("ORA") != -1) {
            int idx = oraErr.lastIndexOf("ORA-");
            return oraErr.substring(idx + 10, oraErr.length()).trim();
        } else
            return oraErr;
    }

    /**
     * 转译中文的URL参数
     *
     * @param cnParameter 原始中文参数值
     * @return 转译后的GBK码的中文参数值<br>
     * 参数为空，或者转译出错，则返回null类型
     */
    public static String encodeURLParameter(String cnParameter) {
        String strParameter = cnParameter;
        try {
            if (isNull(cnParameter)) {
                return null;
            } else {
                strParameter = new String(java.net.URLEncoder.encode(
                        cnParameter, "GBK"));
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return strParameter;
    }

    /**
     * 解析生成in的命名参数
     *
     * @param parameterMap 已使用的命名参数MAP
     * @param list         参数值列表
     * @return
     */
    public static StringBuffer parseArgIn(Map<String, String> parameterMap,
                                          List<String> list) {
        StringBuffer sbf = new StringBuffer();
        String arg = "arg";
        int i;
        for (i = 0; i < list.size() - 1; i++) {
            sbf.append(" :" + arg + i + ",");
            parameterMap.put(arg + i, list.get(i));
        }
        sbf.append(" :" + arg + i);
        parameterMap.put(arg + i, list.get(i));
        return sbf;
    }

    /********************************************* 加密解密 *******************************************/
    private static final String B64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    /**
     * B64Table加密
     *
     * @param instr 原始密码
     * @return 加密密码
     */
    public static String encrypt(String instr) {
        String res = "";
        if (instr == null) {
            instr = "";
        }
        int[] aa = new int[3];
        aa[0] = 0;
        aa[1] = 0;
        aa[2] = 0;
        int[] bb = new int[4];
        // char[] in = instr.toCharArray();
        int length = instr.length();
        for (int i = 0; i < (length + 2) / 3; i++) {
            String middle = "";
            if (length < (i * 3 + 3)) {
                switch (length - i * 3) {
                    case 1: {
                        aa[0] = instr.charAt(i * 3);
                        bb[0] = (aa[0] & 252) >> 2;
                        bb[1] = ((aa[0] & 3) << 4) | ((aa[1] & 240) >> 4);
                        middle = String.valueOf(B64Table.charAt(bb[0]));
                        middle = middle + String.valueOf(B64Table.charAt(bb[1]));
                        middle = middle + "==";
                        break;
                    }
                    case 2: {
                        aa[0] = instr.charAt(i * 3);
                        aa[1] = instr.charAt(i * 3 + 1);
                        bb[0] = (aa[0] & 252) >> 2;
                        bb[1] = ((aa[0] & 3) << 4) | ((aa[1] & 240) >> 4);
                        bb[2] = ((aa[1] & 15) << 2) | ((aa[2] & 192) >> 6);
                        middle = String.valueOf(B64Table.charAt(bb[0]));
                        middle = middle + String.valueOf(B64Table.charAt(bb[1]));
                        middle = middle + String.valueOf(B64Table.charAt(bb[2]));
                        middle = middle + "=";
                        break;
                    }
                }
            } else {
                for (int j = 0; j < 3; j++) {
                    aa[j] = instr.charAt(i * 3 + j);
                }
                bb[0] = (aa[0] & 252) >> 2;
                bb[1] = ((aa[0] & 3) << 4) | ((aa[1] & 240) >> 4);
                bb[2] = ((aa[1] & 15) << 2) | ((aa[2] & 192) >> 6);
                bb[3] = aa[2] & 63;
                for (int j = 0; j < 4; j++) {
                    middle = middle + String.valueOf(B64Table.charAt(bb[j]));
                }
            }
            res = res + middle;
        }
        return res;
    }

    /**
     * －－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－
     *
     * 解密
     *
     * －－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－
     */

    /**
     * @param i
     * @return int
     * @throws
     * @Description: 解密
     * @author Administrator
     * @date 2016年3月23日
     */
    private static int decode1(int i) {
        int result = 0;
        if (i > 64 && i < 91) {
            result = i - 65;
        } else if (i > 96 && i < 123) {
            result = i - 71;
        } else if (i > 47 && i < 58) {
            result = i + 4;
        } else if (i == 43) {
            result = 62;
        } else {
            result = 63;
        }
        return result;
    }

    /**
     * B64Table解密
     *
     * @param input 加密密码
     * @return 原始密码
     */
    public static String decode(String input) {
        String res = "";
        if (input == null) {
            input = "";
        }
        int length = input.length();
        int[] aa = new int[4];
        int[] bb = new int[3];
        if (length % 4 != 0) {
            res = "解密串格式不正确";
        } else {
            for (int i = 0; i < length / 4; i++) {
                for (int j = 0; j < 4; j++) {
                    aa[j] = decode1(input.charAt(i * 4 + j));
                }
                bb[0] = ((aa[0] << 2)) % 256 | ((aa[1] >> 4) & 3);
                bb[1] = ((aa[1] << 4) % 256) | ((aa[2] >> 2) & 15);
                bb[2] = ((aa[2] << 6) % 256) | (aa[3] & 63);
                String middle = String.valueOf((char) bb[0])
                        + String.valueOf((char) bb[1])
                        + String.valueOf((char) bb[2]);
                res = res + middle;
            }
        }
        int k = input.indexOf("=");
        if (k == length - 1) {
            res = res.substring(0, res.length() - 1);
        } else if (k == length - 2) {
            res = res.substring(0, res.length() - 2);
        }
        return res;
    }

    /**
     * MD5 加密
     *
     * @param str
     * @return
     */
    public static String encryptMD5(String str) {
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.reset();
            messageDigest.update(str.getBytes("UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            log.error("NoSuchAlgorithmException caught!");
            System.exit(-1);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        byte[] byteArray = messageDigest.digest();
        StringBuffer md5StrBuff = new StringBuffer();
        for (int i = 0; i < byteArray.length; i++) {
            if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
                md5StrBuff.append("0").append(
                        Integer.toHexString(0xFF & byteArray[i]));
            else
                md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
        }
        return md5StrBuff.toString().toUpperCase();
    }

    /**
     * @param str
     * @param def
     * @return String
     * @throws
     * @Description: 传入一个字符串，如果字符串为空或""，则返回默认字符串，否则返回该字符串
     * @author Administrator
     * @date 2016年3月23日
     */
    public static String getStringNotEmpty(String str, String def) {
        if (isNotEmpty(str)) {
            return str;
        } else {
            return def;
        }
    }

    /**
     * @param arr
     * @return String
     * @throws
     * @Description: 传入一个字符串数组，用特定连接符连接成一个字符串
     * @author Administrator
     * @date 2016年3月23日
     */
    public static String strcat(String[] arr) {
        String str = "";
        if (arr.length != 0) {
            for (int i = 0; i < arr.length; i++) {
                if (i == 0)
                    str += arr[i];
                else
                    str += "," + arr[i];
            }
        }
        return str;
    }

    /**
     * @param str   要分割的字符串
     * @param sChar 要分割的分隔符
     * @return String[] 分割后的字符串数组
     * @throws
     * @Description: 传入一个字符串和分隔符，分割生成一个数组
     * @author Administrator
     * @date 2016年3月23日
     */
    public static String[] splitStr(String str, String sChar) {
        String[] arr = new String[]{};
        if (str.length() > 0) {
            arr = str.split(sChar);
        }
        return arr;
    }

    /**
     * @param s 要反转的字符串
     * @return String 反转后的字符串
     * @throws
     * @Description: 字符串的反转
     * @author Administrator
     * @date 2016年3月23日
     */
    public static String reverse(String s) {
        return ((new StringBuffer(s)).reverse()).toString();
    }

    /**
     * 保留后几位字段，其他使用*替换
     *
     * @param str     需要替换的字符
     * @param size    末位保留的长度
     * @param hideStr 需要影藏的字符
     * @return 替换后的字符串
     */
    public static String hideStr(String str, int size, String hideStr) {
        // 当字符串不为null，且字符串长度比size长，且size大于0
        if (StringUtil.isNotEmpty(str) && str.length() > size && size >= 0) {
            String strTmp = str.substring(str.length() - size);
            for (int i = 0; i <= str.length() - 1 - size; i++) {
                strTmp = hideStr + strTmp;
            }
            return strTmp;
        } else {
            return str;
        }

    }

    /**
     * 截取字符串位数
     *
     * @param o   字符串对象
     * @param bi  开始位数
     * @param ei  结束位数
     * @param def o为null或出错时时的默认值
     * @return
     */
    public static String cutStr(Object o, int bi, int ei, String def) {
        try {
            return ((String) o).substring(bi, ei);
        } catch (Exception e) {
            return def;
        }
    }

    /**
     * 得到一个n位的随机数 第一位不能为0
     *
     * @param n 位数
     * @return
     */
    public static String getRand(int n) {
        Random rnd = new Random();
        String pass = "0";
        int x = rnd.nextInt(9);
        /** 过滤第一位为0 */
        while (x == 0) {
            x = rnd.nextInt(9);
        }
        pass = String.valueOf(x);
        for (int i = 1; i < n; i++) {
            pass = pass + String.valueOf(rnd.nextInt(9));
        }
        return pass;
    }

    /**
     * 所有参数为空的时候返回true
     *
     * @param args
     * @return true false
     */
    public static Boolean isEmptyAll(Object... args) {
        Boolean flag = true;
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof String) {
                if (!isBlank((String) args[i])) {
                    flag = false;
                }
            } else {
                if (null != args[i]) {
                    flag = false;
                }
            }
        }
        return flag;
    }

    /**
     * 只要有一个参数为空就返回true
     *
     * @param args
     * @return true false
     */
    public static Boolean isEmptyOne(Object... args) {
        Boolean flag = false;
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof String) {
                if (isBlank((String) args[i])) {
                    flag = true;
                }
            } else {
                if (null == args[i]) {
                    flag = true;
                }
            }
        }
        return flag;
    }

    /**
     * 把字符串第一个字母转成大写
     *
     * @param str
     * @return
     */
    public static String getFirstUpper(String str) {
        String newStr = "";
        if (str.length() > 0) {
            newStr = str.substring(0, 1).toUpperCase()
                    + str.substring(1, str.length());
        }
        return newStr;
    }

    /**
     * 获取一个字符在一个字符串里出现的次数
     *
     * @param tagetStr
     * @param str
     * @return
     */
    public static int indexOfAll(String tagetStr, String str) {
        int i = 0;
        if (null != tagetStr) {
            i = tagetStr.length() - tagetStr.replace(str, "").length();
        }
        return i;
    }

    /**
     * 转null字符串为""
     *
     * @param str
     * @return
     */
    public static String getNullTo(String str) {
        if (isBlank(str)) {
            str = "";
        }
        return str;
    }

    /**
     * 比较两个Long是否相等
     *
     * @param a
     * @param b
     * @return
     */
    public static boolean equals(Long a, Long b) {
        boolean flag = false;
        if (null == a) {
            a = 0L;
        }
        if (null == b) {
            b = 0L;
        }
        if (a.equals(b)) {
            flag = true;
        }
        return flag;
    }

    /**
     * 比较两个对象是否相等
     *
     * @param a
     * @param b
     * @return
     */
    public static boolean equals(Object a, Object b) {
        boolean flag = false;
        if (null == a) {
            a = "";
        }
        a = String.valueOf(a);
        if (null == b) {
            b = "";
        }
        b = String.valueOf(b);
        if (a.equals(b)) {
            flag = true;
        }
        return flag;
    }

    /**
     * 比较两个字符串是否相等
     *
     * @param a
     * @param b
     * @return
     */
    public static boolean equals(String a, String b) {
        boolean flag = false;
        if (null == a) {
            a = "";
        }
        if (null == b) {
            b = "";
        }
        if (a.equals(b)) {
            flag = true;
        }
        return flag;
    }





    /**
     * 主函数,输入字符得到他的声母, 英文字母返回对应的大写字母 其他非简体汉字返回 '0'
     *
     * @param ch
     * @return
     */
    public static char Char2Alpha(char ch) {
        if (ch >= 'a' && ch <= 'z')
            return (char) (ch - 'a' + 'A');
        if (ch >= 'A' && ch <= 'Z')
            return ch;
        int gb = gbValue(ch);
        if (gb < table[0]) {
            return '0';
        }
        int i;
        for (i = 0; i < 26; ++i) {
            if (match(i, gb))
                break;
        }
        if (i >= 26)
            return '0';
        else
            return alphatable[i];
    }

    public static int[] table = new int[27];

    {// 初始化
        for (int i = 0; i < 27; ++i) {
            table[i] = gbValue(chartable[i]);
        }
    }

    private static boolean match(int i, int gb) {
        if (gb < table[i])
            return false;
        int j = i + 1;
        // 字母Z使用了两个标签
        while (j < 26 && (table[j] == table[i]))
            ++j;
        if (j == 26)
            return gb <= table[j];
        else
            return gb < table[j];
    }

    // 取出汉字的编码
    private static int gbValue(char ch) {
        String str = new String();
        str += ch;
        try {
            byte[] bytes = str.getBytes("GB2312");
            if (bytes.length < 2) {
                return 0;
            }
            return (bytes[0] << 8 & 0xff00) + (bytes[1] & 0xff);
        } catch (Exception e) {
            return 0;
        }

    }

    /**
     * @param SourceStr
     * @return String
     * @throws
     * @Description: 根据一个包含汉字的字符串返回一个汉字拼音首字母的字符串
     * @author Administrator
     * @date 2016年3月23日
     */
    public static String String2Alpha(String SourceStr) {
        String Result = "";
        int StrLength = SourceStr.length();
        int i;
        try {
            for (i = 0; i < StrLength; i++) {
                Result += Char2Alpha(SourceStr.charAt(i));
            }
        } catch (Exception e) {
            Result = "";
        }
        return Result;
    }

    /**
     * 填充左边字符
     *
     * @param source   源字符串
     * @param fillChar 填充字符
     * @param len      填充到的长度
     * @return 填充后的字符串
     */
    public static String fillLeft(String source, char fillChar, int len) {
        StringBuffer ret = new StringBuffer();
        if (null == source)
            ret.append("");
        if (source.length() > len) {
            ret.append(source);
        } else {
            int slen = source.length();
            while (ret.toString().length() + slen < len) {
                ret.append(fillChar);
            }
            ret.append(source);
        }
        return ret.toString();
    }

    /**
     * 填充右边字符
     *
     * @param source   源字符串
     * @param fillChar 填充字符
     * @param len      填充到的长度
     * @return 填充后的字符串
     */
    public static String filRight(String source, char fillChar, int len) {
        StringBuffer ret = new StringBuffer();
        if (null == source)
            ret.append("");
        if (source.length() > len) {
            ret.append(source);
        } else {
            ret.append(source);
            while (ret.toString().length() < len) {
                ret.append(fillChar);
            }
        }
        return ret.toString();
    }

    /**
     * 检测字符是否是数字
     *
     * @param c
     * @return
     */
    public static boolean isDigit(char c) {
        String nums = "0123456789.";
        if (nums.indexOf(String.valueOf(c)) == -1) {
            return false;
        }
        return true;
    }

    /**
     * 检测字符是否为空,为空的时候返回提示
     *
     * @param str
     * @param msg 为空的时候返回提示
     * @return
     */
    public static String isBlankToMsg(String str, String msg) {
        String returnstr = "";
        if (StringUtil.isBlank(str)) {
            returnstr = msg + ",";
        }
        return returnstr;
    }

    /**
     * 截取超长的信息，多余用...
     *
     * @param str 备注
     * @param len 长
     * @return 截取后的信息
     */
    public static String intercept(String str, int len) {
        String newstr = "";
        if (null == str) {
            return newstr;
        }
        if (str.length() > len) {
            newstr = str.substring(0, len) + "...";
        } else {
            newstr = str;
        }
        return newstr;
    }

    /**
     * 转义页面输入的特殊符号
     *
     * @param str
     * @return
     */
    public static String replaceHtml(String str) {
        if (null == str) {
            return "";
        }
        str = StringUtil.replaceString(str, "&", "&amp;");
        str = StringUtil.replaceString(str, "'", "&apos;");
        str = StringUtil.replaceString(str, "\"", "&quot;");
        str = StringUtil.replaceString(str, "\n", "<br>");
        str = StringUtil.replaceString(str, "\t", "&nbsp;&nbsp;");// 替换跳格
        str = StringUtil.replaceString(str, " ", "&nbsp;");// 替换空格
        return str;
    }

    /**
     * 字符串替换 created 2015-12-15
     *
     * @param original 原字符串
     * @param find     需替换字符串
     * @param replace  替换后字符串
     * @return 结果字符串
     */
    public static String replaceString(String original, String find,
                                       String replace) {
        if (original == null) {
            original = "";
        }
        String returnStr = "";
        if (original.indexOf(find) < 0) {
            returnStr = original;
        }
        try {
            while (original.indexOf(find) >= 0) {
                int indexbegin = original.indexOf(find);
                String leftstring = original.substring(0, indexbegin);
                original = original.substring(indexbegin + find.length());
                if (original.indexOf(find) <= 0) {
                    returnStr = returnStr + leftstring + replace + original;
                } else {
                    returnStr = returnStr + leftstring + replace;
                }
            }
            return returnStr;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return original;
    }

    /**
     * 反向转义页面输入的特殊符号
     *
     * @param str
     * @return
     */
    public static String reReplaceHtml(String str) {
        if (null == str) {
            return "";
        }
        str = StringUtil.replaceString(str, "&amp;", "&");
        str = StringUtil.replaceString(str, "&apos;", "'");
        str = StringUtil.replaceString(str, "&quot;", "\"");
        str = StringUtil.replaceString(str, "<br>", "\n");
        str = StringUtil.replaceString(str, "&nbsp;&nbsp;", "\t");// 替换跳格
        str = StringUtil.replaceString(str, "&nbsp;", " ");// 替换空格
        return str;
    }

    /**
     * @param str 指定的字符串
     * @param len 长度
     * @return String 添加空格后的字符串
     * @throws
     * @Description: 对指定的字符串后面添加空格，直到长度达到len指定的长度
     * @author Lm
     * @date 2016年3月23日
     */
    public static String expandString(String str, int len) {
        str = str.trim();
        int j = str.getBytes().length;
        for (int i = 0; i < len - j; i++) {
            str = str + " ";
        }

        return str;
    }

    /**
     * @param str 指定字符串
     * @return String 去掉首字母后的字符串
     * @throws
     * @Description: 去除指定字符串的首字母，用于非身份证的证件处理
     * @author Lm
     * @date 2016年3月23日
     */
    //
    public static String wipeOffString(String str) {
        String s = str.substring(0, 1);
        if (s.equals("C") || s.equals("D") || s.equals("E") || s.equals("F")
                || s.equals("G")) {
            str = str.substring(1, str.length());
        }
        return str;
    }

    /**
     * 身份证15位转18位
     *
     * @param idCard 15位身份证号码
     * @return 18位身份证号码
     */
    public static String id15to18(String idCard) {
        String identifyCode = "";
        StringBuffer idCard18 = new StringBuffer(identifyCode.trim());
        // 加权因子
        // int[] weight = {7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
        // 校验码值
        char[] checkBit = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3',
                '2'};
        int sum = 0;
        // 15位的身份证
        if (idCard != null && idCard.length() == 15) {
            idCard18.insert(6, "19");
            for (int index = 0; index < idCard18.length(); index++) {
                char c = idCard18.charAt(index);
                int ai = Integer.parseInt(new Character(c).toString());
                // sum = sum+ai*weight[index];
                // 加权因子的算法
                int Wi = ((int) Math.pow(2, idCard18.length() - index)) % 11;
                sum = sum + ai * Wi;
            }
            int indexOfCheckBit = sum % 11; // 取模
            idCard18.append(checkBit[indexOfCheckBit]);
            identifyCode = idCard18.toString();
        }

        return identifyCode;
    }

    /**
     * 将URL参数转码为GBK格式
     *
     * @param str 待转码字符串（ISO8859-1）
     * @return String转码后的字符串（GBK）
     * @author jsl added on 2010-01-12
     */
    public static String urlParaEncoder(String str) {
        String newStr = "";
        if (isNotEmpty(str.trim())) {
            try {
                newStr = new String(str.getBytes("ISO8859-1"), "GBK");
            } catch (UnsupportedEncodingException e) {
                log.error(e.getMessage());
            }
        }
        return newStr;
    }

    /**
     * 将字符串转化为日期
     *
     * @param tmp 要转化日期的String
     * @param df  日期格式
     * @return Date 类型
     */
    public static Date StringToDate(String tmp, String df) {
        if (isNull(df)) {
            throw new IllegalArgumentException("传入的日期格式有误，请确认参数df是否正确！");
        } else {
            if (StringUtil.isNull(tmp)) {
                return null;
            }
            Date tmpDate = null;
            SimpleDateFormat formatter = new SimpleDateFormat(df);
            try {
                tmpDate = formatter.parse(tmp.trim());
                return tmpDate;
            } catch (ParseException e) {
                log.error(e.getMessage());
                return null;
            }
        }
    }

    /**
     * @param strs 字符串列表
     * @return 是否包含空字符串
     * @Description:是否包含空字符串
     * @author xiequn
     * @date 2016年1月12日
     */
    public static boolean hasBlank(String... strs) {
        if (CollectionUtil.isEmpty(strs)) {
            return true;
        }

        for (String str : strs) {
            if (isBlank(str)) {
                return true;
            }
        }
        return false;
    }

    /**
     * @param str 被转换的字符串
     * @return 转换后的字符串
     * @Description:当给定字符串为null时，转换为Empty
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String nullToEmpty(String str) {
        return str == null ? EMPTY : str;
    }

    /**
     * @param str 被转换的字符串
     * @return 转换后的字符串
     * @Description:当给定字符串为空字符串时，转换为<code>null</code>
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String emptyToNull(String str) {
        return isEmpty(str) ? null : str;
    }

    /**
     * @param strs 字符串列表
     * @return 是否包含空字符串
     * @Description:是否包含空字符串
     * @author xiequn
     * @date 2016年1月12日
     */
    public static boolean hasEmpty(String... strs) {
        for (String str : strs) {
            if (isEmpty(str)) {
                return true;
            }
        }
        return false;
    }

    /**
     * @param str 字符串
     * @return 处理后的字符串
     * @Description:去除字符串两边的空格符，如果为null返回null
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String trim(String str) {
        return (null == str) ? null : str.trim();
    }

    /**
     * @param getOrSetMethodName
     * @return 如果是set或get方法名，返回field， 否则null
     * @Description:获得set或get方法对应的标准属性名<br/> 例如：setName 返回 name
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String getGeneralField(String getOrSetMethodName) {
        if (getOrSetMethodName.startsWith("get")
                || getOrSetMethodName.startsWith("set")) {
            return cutPreAndLowerFirst(getOrSetMethodName, 3);
        }
        return null;
    }

    /**
     * @param fieldName 属性名
     * @return setXxx
     * @Description:生成set方法名<br/> 例如：name 返回 setName
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String genSetter(String fieldName) {
        return upperFirstAndAddPre(fieldName, "set");
    }

    /**
     * @param fieldName 属性名
     * @return getXxx
     * @Description:生成get方法名
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String genGetter(String fieldName) {
        return upperFirstAndAddPre(fieldName, "get");
    }

    /**
     * @param str       被处理的字符串
     * @param preLength 去掉的长度
     * @return 处理后的字符串，不符合规范返回null
     * @Description:去掉首部指定长度的字符串并将剩余字符串首字母小写<br/> 例如：str=setName, preLength=3 ->
     * return name
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String cutPreAndLowerFirst(String str, int preLength) {
        if (str == null) {
            return null;
        }
        if (str.length() > preLength) {
            char first = Character.toLowerCase(str.charAt(preLength));
            if (str.length() > preLength + 1) {
                return first + str.substring(preLength + 1);
            }
            return String.valueOf(first);
        }
        return null;
    }

    /**
     * @param str       被处理的字符串
     * @param preString 添加的首部
     * @return 处理后的字符串
     * @Description:原字符串首字母大写并在其首部添加指定字符串 例如：str=name, preString=get -> return
     * getName
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String upperFirstAndAddPre(String str, String preString) {
        if (str == null || preString == null) {
            return null;
        }
        return preString + upperFirst(str);
    }

    /**
     * @param str 字符串
     * @return 字符串
     * @Description:大写首字母<br> 例如：str = name, return Name
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String upperFirst(String str) {
        return Character.toUpperCase(str.charAt(0)) + str.substring(1);
    }

    /**
     * @param str 字符串
     * @return 字符串
     * @Description:小写首字母<br> 例如：str = Name, return name
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String lowerFirst(String str) {
        return Character.toLowerCase(str.charAt(0)) + str.substring(1);
    }

    /**
     * @param str    字符串
     * @param prefix 前缀
     * @return 切掉后的字符串，若前缀不是 preffix， 返回原字符串
     * @Description:去掉指定前缀
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String removePrefix(String str, String prefix) {
        if (str != null && str.startsWith(prefix)) {
            return str.substring(prefix.length());
        }
        return str;
    }

    /**
     * @param str    字符串
     * @param prefix 前缀
     * @return 切掉后的字符串，若前缀不是 prefix， 返回原字符串
     * @Description:忽略大小写去掉指定前缀
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String removePrefixIgnoreCase(String str, String prefix) {
        if (str != null && str.toLowerCase().startsWith(prefix.toLowerCase())) {
            return str.substring(prefix.length());
        }
        return str;
    }

    /**
     * @param str    字符串
     * @param suffix 后缀
     * @return 切掉后的字符串，若后缀不是 suffix， 返回原字符串
     * @Description:去掉指定后缀
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String removeSuffix(String str, String suffix) {
        if (str != null && str.endsWith(suffix)) {
            return str.substring(0, str.length() - suffix.length());
        }
        return str;
    }

    /**
     * @param str    字符串
     * @param suffix 后缀
     * @return 切掉后的字符串，若后缀不是 suffix， 返回原字符串
     * @Description:忽略大小写去掉指定后缀
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String removeSuffixIgnoreCase(String str, String suffix) {
        if (str != null && str.toLowerCase().endsWith(suffix.toLowerCase())) {
            return str.substring(0, str.length() - suffix.length());
        }
        return str;
    }

    /**
     * @param str 被清理的字符串
     * @return 清理后的字符串
     * @Description:清理空白字符
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String cleanBlank(String str) {
        if (str == null) {
            return null;
        }

        return str.replaceAll("\\s*", EMPTY);
    }

    /**
     * @param str       被切分的字符串
     * @param separator 分隔符字符
     * @return 切分后的集合
     * @Description:切分字符串<br/> a#b#c -> [a,b,c] a##b#c -> [a,"",b,c]
     * @author xiequn
     * @date 2016年1月12日
     */
    public static List<String> split(String str, char separator) {
        return split(str, separator, 0);
    }

    /**
     * @param str       被切分的字符串
     * @param separator 分隔符字符
     * @param limit     限制分片数
     * @return 切分后的集合
     * @Description:切分字符串
     * @author xiequn
     * @date 2016年1月12日
     */
    public static List<String> split(String str, char separator, int limit) {
        if (str == null) {
            return null;
        }
        List<String> list = new ArrayList<String>(limit == 0 ? 16 : limit);
        if (limit == 1) {
            list.add(str);
            return list;
        }

        boolean isNotEnd = true; // 未结束切分的标志
        int strLen = str.length();
        StringBuilder sb = new StringBuilder(strLen);
        for (int i = 0; i < strLen; i++) {
            char c = str.charAt(i);
            if (isNotEnd && c == separator) {
                list.add(sb.toString());
                // 清空StringBuilder
                sb.delete(0, sb.length());

                // 当达到切分上限-1的量时，将所剩字符全部作为最后一个串
                if (limit != 0 && list.size() == limit - 1) {
                    isNotEnd = false;
                }
            } else {
                sb.append(c);
            }
        }
        list.add(sb.toString());
        return list;
    }

    /**
     * @param str       被切分的字符串
     * @param delimiter 分隔符
     * @return 字符串
     * @Description:切分字符串
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String[] split(String str, String delimiter) {
        if (str == null) {
            return null;
        }
        if (str.trim().length() == 0) {
            return new String[]{str};
        }

        int dellen = delimiter.length(); // del length
        int maxparts = (str.length() / dellen) + 2; // one more for the last
        int[] positions = new int[maxparts];

        int i, j = 0;
        int count = 0;
        positions[0] = -dellen;
        while ((i = str.indexOf(delimiter, j)) != -1) {
            count++;
            positions[count] = i;
            j = i + dellen;
        }
        count++;
        positions[count] = str.length();

        String[] result = new String[count];

        for (i = 0; i < count; i++) {
            result[i] = str.substring(positions[i] + dellen, positions[i + 1]);
        }
        return result;
    }

    /**
     * @param string    String
     * @param fromIndex 开始的index（包括）
     * @param toIndex   结束的index（不包括）
     * @return 字串
     * @Description:改进JDK subString<br>
     * index从0开始计算，最后一个字符为-1<br>
     * 如果from和to位置一样，返回 "" example: abcdefgh 2 3 -> c
     * abcdefgh 2 -3 -> cde
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String sub(String string, int fromIndex, int toIndex) {
        int len = string.length();

        if (fromIndex < 0) {
            fromIndex = len + fromIndex;

            if (toIndex == 0) {
                toIndex = len;
            }
        }

        if (toIndex < 0) {
            toIndex = len + toIndex;
        }

        if (toIndex < fromIndex) {
            int tmp = fromIndex;
            fromIndex = toIndex;
            toIndex = tmp;
        }

        if (fromIndex == toIndex) {
            return EMPTY;
        }

        char[] strArray = string.toCharArray();
        char[] newStrArray = Arrays.copyOfRange(strArray, fromIndex, toIndex);
        return new String(newStrArray);
    }

    /**
     * @param string  字符串
     * @param toIndex 切割到的位置（不包括）
     * @return 切割后的字符串
     * @Description:切割前部分
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String subPre(String string, int toIndex) {
        return sub(string, 0, toIndex);
    }

    /**
     * @param string    字符串
     * @param fromIndex 切割开始的位置（包括）
     * @return 切割后的字符串
     * @Description:切割后部分
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String subSuf(String string, int fromIndex) {
        if (isEmpty(string)) {
            return null;
        }
        return sub(string, fromIndex, string.length());
    }

    /**
     * @param c     被重复的字符
     * @param count 重复的数目
     * @return 重复字符字符串
     * @Description:重复某个字符
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String repeat(char c, int count) {
        char[] result = new char[count];
        for (int i = 0; i < count; i++) {
            result[i] = c;
        }
        return new String(result);
    }

    /**
     * @param str   被重复的字符
     * @param count 重复的数目
     * @return 重复字符字符串
     * @Description:重复某个字符串
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String repeat(String str, int count) {

        // 检查
        final int len = str.length();
        final long longSize = (long) len * (long) count;
        final int size = (int) longSize;
        if (size != longSize) {
            throw new ArrayIndexOutOfBoundsException(
                    "Required String length is too large: " + longSize);
        }

        final char[] array = new char[size];
        str.getChars(0, len, array, 0);
        int n;
        for (n = len; n < size - n; n <<= 1) {// n <<= 1相当于n *2
            System.arraycopy(array, 0, array, n, n);
        }
        System.arraycopy(array, 0, array, n, size - n);
        return new String(array);
    }

    /**
     * @param str1 字符串1
     * @param str2 字符串2
     * @return 是否非空相同
     * @Description:比较两个字符串是否相同，如果为null或者空串则算不同
     * @author xiequn
     * @date 2016年1月12日
     */
    public static boolean equalsNotEmpty(String str1, String str2) {
        if (isEmpty(str1)) {
            return false;
        }
        return str1.equals(str2);
    }

    /**
     * @param template 文本模板，被替换的部分用 {key} 表示
     * @param map      参数值对
     * @return 格式化后的文本
     * @Description:格式化文本
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String format(String template, Map<?, ?> map) {
        if (null == map || map.isEmpty()) {
            return template;
        }

        for (Entry<?, ?> entry : map.entrySet()) {
            template = template.replace("{" + entry.getKey() + "}", entry
                    .getValue().toString());
        }
        return template;
    }

    /**
     * @param objs 对象数组
     * @return 字符串
     * @Description:将多个对象字符化<br> 每个对象字符化后直接拼接，无分隔符
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String str(Object... objs) {
        StringBuilder sb = new StringBuilder();
        for (Object obj : objs) {
            sb.append(obj);
        }
        return sb.toString();
    }

    /**
     * @param bytes   byte数组
     * @param charset 字符集
     * @return 字符串
     * @Description:将byte数组转为字符串
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String str(byte[] bytes, String charset) {
        return new String(bytes, Charset.forName(charset));
    }

    /**
     * @param camelCaseStr 转换前的驼峰式命名的字符串
     * @return 转换后下划线大写方式命名的字符串
     * @Description: 将驼峰式命名的字符串转换为下划线方式。如果转换前的驼峰式命名的字符串为空，则返回空字符串。</br>
     * 例如：HelloWorld->hello_world
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String toUnderlineCase(String camelCaseStr) {
        if (camelCaseStr == null) {
            return null;
        }

        final int length = camelCaseStr.length();
        StringBuilder sb = new StringBuilder();
        char c;
        boolean isPreUpperCase = false;
        for (int i = 0; i < length; i++) {
            c = camelCaseStr.charAt(i);
            boolean isNextUpperCase = true;
            if (i < (length - 1)) {
                isNextUpperCase = Character.isUpperCase(camelCaseStr
                        .charAt(i + 1));
            }
            if (Character.isUpperCase(c)) {
                if (!isPreUpperCase || !isNextUpperCase) {
                    if (i > 0)
                        sb.append(UNDERLINE);
                }
                isPreUpperCase = true;
            } else {
                isPreUpperCase = false;
            }
            sb.append(Character.toLowerCase(c));
        }
        return sb.toString();
    }

    /**
     * @param name 转换前的下划线大写方式命名的字符串
     * @return 转换后的驼峰式命名的字符串
     * @Description: 将下划线方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。</br>
     * 例如：hello_world->HelloWorld
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String toCamelCase(String name) {
        if (name == null) {
            return null;
        }
        if (name.contains(UNDERLINE)) {
            name = name.toLowerCase();

            StringBuilder sb = new StringBuilder(name.length());
            boolean upperCase = false;
            for (int i = 0; i < name.length(); i++) {
                char c = name.charAt(i);

                if (c == '_') {
                    upperCase = true;
                } else if (upperCase) {
                    sb.append(Character.toUpperCase(c));
                    upperCase = false;
                } else {
                    sb.append(c);
                }
            }
            return sb.toString();
        } else
            return name;
    }

    /**
     * @param str    字符串
     * @param prefix 前缀
     * @param suffix 后缀
     * @return 是否被包装
     * @Description: 指定字符串是否被包装
     * @author xiequn
     * @date 2016年1月12日
     */
    public static boolean isWrap(String str, String prefix, String suffix) {
        return str.startsWith(prefix) && str.endsWith(suffix);
    }

    /**
     * @param str     字符串
     * @param wrapper 包装字符串
     * @return 是否被包装
     * @Description: 指定字符串是否被同一字符包装（前后都有这些字符串）
     * @author xiequn
     * @date 2016年1月12日
     */
    public static boolean isWrap(String str, String wrapper) {
        return isWrap(str, wrapper, wrapper);
    }

    /**
     * @param str     字符串
     * @param wrapper 包装字符
     * @return 是否被包装
     * @Description: 指定字符串是否被同一字符包装（前后都有这些字符串）
     * @author xiequn
     * @date 2016年1月12日
     */
    public static boolean isWrap(String str, char wrapper) {
        return isWrap(str, wrapper, wrapper);
    }

    /**
     * @param str        字符串
     * @param prefixChar 前缀
     * @param suffixChar 后缀
     * @return 是否被包装
     * @Description: 指定字符串是否被包装
     * @author xiequn
     * @date 2016年1月12日
     */
    public static boolean isWrap(String str, char prefixChar, char suffixChar) {
        return str.charAt(0) == prefixChar
                && str.charAt(str.length() - 1) == suffixChar;
    }

    /**
     * @param str       字符串
     * @param minLength 最小长度
     * @param padChar   补充的字符
     * @return 补充后的字符串
     * @Description: 补充字符串以满足最小长度 StrUtil.padPre("1", 3, '0');//"001"
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String padPre(String str, int minLength, char padChar) {
        if (str.length() >= minLength) {
            return str;
        }
        StringBuilder sb = new StringBuilder(minLength);
        for (int i = str.length(); i < minLength; i++) {
            sb.append(padChar);
        }
        sb.append(str);
        return sb.toString();
    }

    /**
     * @param str       字符串
     * @param minLength 最小长度
     * @param padChar   补充的字符
     * @return 补充后的字符串
     * @Description: 补充字符串以满足最小长度 StrUtil.padEnd("1", 3, '0');//"100"
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String padEnd(String str, int minLength, char padChar) {
        if (str.length() >= minLength) {
            return str;
        }
        StringBuilder sb = new StringBuilder(minLength);
        sb.append(str);
        for (int i = str.length(); i < minLength; i++) {
            sb.append(padChar);
        }
        return sb.toString();
    }

    /**
     * @return StringBuilder对象
     * @Description: 创建StringBuilder对象
     * @author xiequn
     * @date 2016年1月12日
     */
    public static StringBuilder builder() {
        return new StringBuilder();
    }

    /**
     * @param capacity 默认长度
     * @return StringBuilder对象
     * @Description: 创建StringBuilder对象
     * @author xiequn
     * @date 2016年1月12日
     */
    public static StringBuilder builder(int capacity) {
        return new StringBuilder(capacity);
    }

    /**
     * @param strs 不定参数字符串
     * @return StringBuilder对象
     * @Description: 创建StringBuilder对象
     * @author xiequn
     * @date 2016年1月12日
     */
    public static StringBuilder builder(String... strs) {
        final StringBuilder sb = new StringBuilder();
        for (String str : strs) {
            sb.append(str);
        }
        return sb;
    }

    /**
     * @param template 文本模板，被替换的部分用 {} 表示
     * @param values   参数值
     * @return 格式化后的文本
     * @Description: 格式化文本
     * @author xiequn
     * @date 2016年1月12日
     */
    public static String format(String template, Object... values) {
        if (CollectionUtil.isEmpty(values) || isBlank(template)) {
            return template;
        }

        final StringBuilder sb = new StringBuilder();
        final int length = template.length();

        int valueIndex = 0;
        char currentChar;
        for (int i = 0; i < length; i++) {
            if (valueIndex >= values.length) {
                sb.append(sub(template, i, length));
                break;
            }

            currentChar = template.charAt(i);
            if (currentChar == '{') {
                final char nextChar = template.charAt(++i);
                if (nextChar == '}') {
                    sb.append(values[valueIndex++]);
                } else {
                    sb.append('{').append(nextChar);
                }
            } else {
                sb.append(currentChar);
            }

        }

        return sb.toString();
    }

    // 国标码和区位码转换常量
    static final int GB_SP_DIFF = 160;

    // 存放国标一级汉字不同读音的起始区位码
    static final int[] secPosValueList = {1601, 1637, 1833, 2078, 2274, 2302,
            2433, 2594, 2787, 3106, 3212, 3472, 3635, 3722, 3730, 3858, 4027,
            4086, 4390, 4558, 4684, 4925, 5249, 5600};

    // 存放国标一级汉字不同读音的起始区位码对应读音
    static final char[] firstLetter = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
            'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'w', 'x',
            'y', 'z'};

    // 获取一个字符串的拼音码
    public static String getFirstLetter(String oriStr) {
        String str = oriStr.toLowerCase();
        StringBuffer buffer = new StringBuffer();
        char ch;
        char[] temp;
        for (int i = 0; i < str.length(); i++) { // 依次处理str中每个字符
            ch = str.charAt(i);
            temp = new char[]{ch};
            byte[] uniCode = new String(temp).getBytes();
            if (uniCode[0] < 128 && uniCode[0] > 0) { // 非汉字
                buffer.append(temp);
            } else {
                buffer.append(convert(uniCode));
            }
        }
        return buffer.toString().toUpperCase();
    }

    static char convert(byte[] bytes) {
        char result = '-';
        int secPosValue = 0;
        int i;
        for (i = 0; i < bytes.length; i++) {
            bytes[i] -= GB_SP_DIFF;
        }
        secPosValue = bytes[0] * 100 + bytes[1];
        for (i = 0; i < 23; i++) {
            if (secPosValue >= secPosValueList[i]
                    && secPosValue < secPosValueList[i + 1]) {
                result = firstLetter[i];
                break;
            }
        }
        return result;
    }

    /**
     * 字符串null时返回""
     *
     * @param str
     * @return
     */
    public static String null2Str(String str) {
        return str == null ? "" : str;
    }

}
